<?php

/**
 * Clase controladora frontal que recibe las peticiones y las delega
 * al controlador y metodo solicitado
 * @author Robert babilonia <bobbabilon2@gmail.com>
 * @todo agregar una clase seguridad que permita validar si la llamada se realiza
 * desde el controlador frontal
 * 
 */
final class CommanderApp {

    /**
     * @var array contiene el arreglo con las librerias necesarias para el funcionamiento del frame
     * LIBRERIAS DEL CORE, NO ELIMINAR.
     * NECESARIAS PARA EL CORRECTO FUNCIONAMIENTO DEL FRAME
     */
    private static $core_libs = array(
        'commander_controller.php', 'commander_view.php', 'commander_utils.php', 'libs/active_record/active_record_base.php', 'libs/client_data.php'
    );

    /**
     * Arreglo con variables de configuracion definidas en el config.php
     * @var arrea 
     */
    private static $config = array();

    /**
     * Da inicio a los servicios principales del frame, cargando la configuracion y
     * llamando al despachador
     */
    public static function __init() {


        try {

            try {
                // se define los manejadores de errores por defecto
                ini_set('display_errors', 'On');
                //capturador de errores
                set_error_handler('CommanderException::frame_error_handler');
                //capturador de errores fatales
                register_shutdown_function('CommanderException::fatal_error_shutdown_handler');
                //capturador de excepciones
                set_exception_handler('CommanderException::frame_exception_handler');
                //metodo de autocarga de modelos
                spl_autoload_register('CommanderApp::commander_autoload', TRUE);

                //inicio de manejo de sesiones
                CommanderSession::start();
                //se cargan las configuraciones
                self::init_config();

                //se pasa la peticion al controlador frontal para su procesamiento
                self::dispatcher();


                /**
                 * Manejo principal de las excepciones, todas las generadas en los modelos,
                 * controladores, librerias o cualquier otra clase seran capturados en esta 
                 * seccion
                 * 
                 */
            } catch (CommanderException $excepcion) {//captura las excepciones del tipo Commander
                $excepcion->get_exception();
            }
        } catch (Exception $excepcion) {//Captura excepciones de cualquier otro tipo
            CommanderException::catch_exception($excepcion);
        }
    }

    /**
     * Inicializacion del manejo de peticiones desde controlador principal
     * @throws CommanderException
     */
    public static function dispatcher() {

        //Inicio de control de salida de la respuesta al navegador
        ob_start();
        $router = new CommanderRouter();
        $url = URL_PATH;
        $router->rewrite(URL_PARAMS);
        $var = $router->get();


        //se setean las variables recibidas por get
        $_GET = array_merge($var["parameters"], $_GET);

        $modulo = $var["module"];
        $controlador = $var["controller"];

        /*
         * verifica si se hace una llamada a un metodo especifico, de
         * lo contrario realiza la llamada al metodo por defecto index
         */
        $metodo = ($var["action"] == "" || $var["action"] === NULL ) ? "index" : $var["action"];

        // se incluye y se llama al controlador dentro del modulo correspondiente
        $controller_dir = MODULE_PATH . $modulo . DIRECTORY_SEPARATOR . "controllers" . DIRECTORY_SEPARATOR . $controlador . "_controller.php";
        if (is_file($controller_dir)) {

            CommanderSession::register("module", $modulo); // se guarda el modulo de la peticion como variable de sesion
            include_once $controller_dir;
            $control = ucfirst($controlador) . "Controller";
            // se instancia el controlador y se indica el identificador y el modulo del mismo
            $controlador_obj = new $control($controlador, $modulo);
            // se llama al metodo del controlador si el mismo existe
            if (method_exists($controlador_obj, $metodo)) {

                // se llama al metodo con sus correspondientes parametros
                call_user_func_array(array(&$controlador_obj, $metodo), $var["parameters"]);
            } else {

                throw new CommanderException(ERROR_METHOD_NOT_EXIST . " " . $metodo);
            }
        } else {

            throw new CommanderException(ERROR_BAD_URL_CONTROLLER . " " . $controller_dir);
        }
    }

    /**
     * Metodo definido como autoload para autocarga de modelos
     * @param string $class_name Identificador de la clase a autocargar
     * @throws CommanderException
     */
    public static function commander_autoload($class_name) {

        //verifica si esta seteada la autocarga de modelos
        if (self::get_config('MODEL_AUTOLOAD') === TRUE) {


            if (CommanderSession::exist("module")) {

                $modulo = CommanderSession::get("module");
                $file = MODULE_PATH . $modulo . DIRECTORY_SEPARATOR . 'models' . DIRECTORY_SEPARATOR . "$class_name.php";

                if (file_exists($file)) {// se busca primero el modelo en el modulo
                    require_once $file;
                } else { //si no existe s ebusca en el direcotio de modelos globales
                    $file = MODEL_PATH . "$class_name.php";

                    if (file_exists($file)) {

                        require_once $file;
                    } else {

                        throw new CommanderException(ERROR_MODEL_NOT_FOUND . $class_name);
                    }
                }
            } else {

                throw new CommanderException(ERROR_MODULE_NOT_SET . $class_name);
            }
        } else {

            throw new CommanderException(ERROR_AUTOLOAD_NOT_SET . $class_name);
        }
    }

    /**
     * Carga la configuracion principal de la aplicacion, basado en el config.php
     * Carga las librerias del frame y las del usuario
     */
    public static function init_config() {


        self::$config = include INCLUDE_PATH . 'config/config.php';

        //se setea el lenguaje de la aplicacion
        self::set_locale();
        // se incluye el archivo de mensajes globales
        include_once INCLUDE_PATH . 'config/system_mesages.php';

        //se cargan las librerias del core
        self::load_core_libs(self::$core_libs);

        //se cargan las librerias del usuario
        self::load_user_libs(include INCLUDE_PATH . 'config/libs.php');

        //inicializa las librerias de activerecord para el manejo d elos modelos
        self::init_models();
    }

    /**
     * Inicializa los componentes de ActiveRecord para usarlo en el framework
     * @throws CommanderException
     */
    private final static function init_models() {

        /**
         * Valida la version de php usada en el sistema
         */
        if (!defined('PHP_VERSION_ID') || PHP_VERSION_ID < 50300) {
            throw new CommanderException(ERROR_ACTIVE_RECORD_REQUIRED . PHP_VERSION_ID, 500);
        }

        // inicializa ActiveRecord
        $connections = self::get_config('CONECTIONS_ARRAY');
        ActiveRecord\Config::initialize(function($cfg) use ($connections) {

            $cfg->set_connections($connections);
        });
    }

    /**
     * Carga las librerias especificadas del core
     * @author Robert Babilonia <bobbabilon2@gmail.com>
     * @param array $libs_array
     * @throws CommanderException
     */
    private static function load_core_libs($libs_array) {

        $lib_path = CORE_PATH;

        if (is_array($libs_array) && count($libs_array) > 0) {//verifica que se recibe un arreglo
            foreach ($libs_array as $lib) {

                $filename = $lib_path . $lib;

                if (is_file($filename)) {

                    require_once $filename;
                } else {

                    throw new CommanderException(ERROR_LIB_NOT_FOUND . $lib);
                }
            }
        } elseif (!is_array($libs_array)) {

            $filename = $lib_path . $libs_array;

            if (is_file($filename)) {

                require_once $filename;
            } else {

                throw new CommanderException(ERROR_LIB_NOT_FOUND . $libs_array);
            }
        }
    }

    /**
     * Carga las librerias especificadas por el usuario, si existen las carga del core, 
     * de lo contrario las busca en /libs del usuario
     * @author Robert Babilonia <bobbabilon2@gmail.com>
     * @param array $libs_array
     * @throws CommanderException
     */
    private static function load_user_libs($libs_array) {

        if (is_array($libs_array) && count($libs_array) > 0) {//verifica que se recibe un arreglo
            foreach ($libs_array as $lib) {

                $filename_core = CORE_PATH . $lib;
                $filename_user = LIB_PATH . $lib;

                if (is_file($filename_core)) {

                    require_once $filename_core;
                } elseif (is_file($filename_user)) {

                    require_once $filename_user;
                } else {

                    throw new CommanderException(ERROR_LIB_NOT_FOUND . $lib);
                }
            }
        } elseif (!is_array($libs_array)) {

            $filename_core = CORE_PATH . $libs_array;
            $filename_user = LIB_PATH . $libs_array;

            if (is_file($filename_core)) {

                require_once $filename_core;
            } elseif (is_file($filename_user)) {

                require_once $filename_user;
            } else {

                throw new CommanderException(ERROR_LIB_NOT_FOUND . $lib);
            }
        }
    }

    public static function get_core_libs() {

        return self::$core_libs;
    }

    public static function get_config($index = NULL) {


        if ($index) {
            if (isset(self::$config[$index])) {
                return self::$config[$index];
            } else {

                return FALSE;
            }
        } else {
            return self::$config;
        }
    }

    /**
     * Define el idioma a usar por la aplicacion, si el mismo no ha sido definido 
     * en el request: post o get se usa el definido por defecto en el archivo
     * de configuracion del frame
     * @param string $path Ruta del directorio locale
     * 
     */
    public static function set_locale($path = LOCALE_PATH) {


        if (extension_loaded('gettext')) {
            bindtextdomain("messages", $path);
            textdomain("messages");
            bind_textdomain_codeset($path, 'UTF-8');
        }

        if (isset($_REQUEST['locale']) || CommanderSession::exist("locale")) {



            if (isset($_REQUEST['locale'])) {

                $locale = $_REQUEST['locale'];
            } else {
                $locale = CommanderSession::get("locale");
            }
            //CommanderLogger::notice_log($locale,'locale');
            CommanderSession::register("locale", $locale);
        } else {

            $locale = self::get_config('DEFAULT_LOCALE');
        }
        putenv("LC_ALL=" . $locale);
        setlocale(LC_ALL, $locale);
        // se guarda la codificacion  como variable de session
    }

}

?>